// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

part of dart.core;

/**
 * Error对象在发生程序故障时被抛出。
 *
 * `Error`对象表示一个程序员应该避免出现的程序故障。
 *
 * 例如，使用无效的参数调用函数，甚至是参数的数目出错，
 * 或者在函数不允许的时候调用它。
 *
 * 这些都不是调用者期望，或应该捕获的。
 * 如果发生这些情况，那么程序一定是有问题的，并且终止程序可能是最安全的做法。
 *
 * 当一个函数决定抛出Error的时候，它发生的环境、条件应该描述清楚。
 * 并且，它们应该是可检测和可预测的，以便程序员在使用函数的时候可以避免引起错误。
 *
 * 此类情况通常使用"must"或"must not"这样的关键字来描述条件，
 * 如果你在函数的文档中看到了这样的关键字，
 * 那么在不满足要求的时候，很有可能会产生一个Error并抛出。
 *
 * 例如， 在[String.contains]中的描述：
 *
 *        `startIndex` must not be negative or greater than `length`.
 *
 * 在这种情况下，如果`startIndex`是负数，或者太大，
 * 则会抛出错误。
 *
 * 在调用一个函数之前，如果未发现使用条件，那么被调用的函数不应该抛出错误。
 * 它可能仍然会抛出一个值，
 * 但是调用者必须捕获抛出的值，使它实际上成为另一个结果，而不是Error。
 * 抛出的对象可以选择实现[Exception]来记录特殊情况，而不是错误，
 * 除非没有其它记录外的情况。
 *
 * 在Dart中，所有非`null`的值都能被抛出。而继承`Error`的对象会特殊处理：
 * 它们会第一时间被抛出，在抛出时间点的堆栈信息会被记录、保存在Error对象中。
 * 它可以使用[stackTrace]的getter方法来恢复。
 * 对于仅仅只是实现了`Error`接口，而没有继承它的Error对象，
 * 将不会自动保存堆栈信息。
 *
 * Error对象也用于系统范围的故障，比如栈溢出，或内存不足。
 *
 * Error在将要被捕获之前，并没有被创建，子类也没有必要去区分Error。
 * 同时，为了使各组相关的Error便于创建，子类使用固定的Error消息创建对象。
 * 例如，在`startIndex`不在`0..length`范围的时候，
 * 如果[String.contains]方法要使用[RangeError]对象，
 * 可以通过`new RangeError.range(startIndex, 0, length)`轻松的创建。
 */
class Error {
  Error();  // 防止用作mixin。

  /**
   * 安全地将一个值转换成一个[String]描述。
   *
   * 它保证一定不会进行任何抛出操作，
   * 所以它并不会使用对象的toString方法（重写toString的时候可能抛出异常/错误）。
   */
  static String safeToString(Object object) {
    if (object is num || object is bool || null == object) {
      return object.toString();
    }
    if (object is String) {
      return _stringToSafeString(object);
    }
    return _objectToString(object);
  }

  /** Convert string to a valid string literal with no control characters. */
  external static String _stringToSafeString(String string);

  external static String _objectToString(Object object);

  /** 堆栈轨迹。 */
  external StackTrace get stackTrace;
}

/**
 * 当断言语句失败时，Error被运行时系统抛出。
 */
class AssertionError extends Error {
  AssertionError();
  String toString() => "Assertion failed";
}

/**
 * 当类型断言失败时，Error被运行时系统抛出。
 */
class TypeError extends AssertionError {
}

/**
 * 当强制转换操作失败时，Error被运行时系统抛出。
 */
class CastError extends Error {
}

/**
 * 当试图抛出空值throw [:null:]时，Error被抛出。
 */
class NullThrownError extends Error {
  String toString() => "Throw of null.";
}

/**
 * 当函数被传入一个不能被接受的参数时，Error被抛出。
 */
class ArgumentError extends Error {
  /** Whether value was provided. */
  final bool _hasValue;
  /** 无效值。 */
  final invalidValue;
  /** 无效参数的名称，如果有的话。*/
  final String name;
  /** 描述问题的信息。 */
  final message;

  /**
   * [message]描述了出错的参数。
   *
   * 现有代码可能使用`message`来保存无效值。
   * 如果`message`不是字符串[String]，它会被假定是一个值，而不是消息。
   */
  ArgumentError([this.message])
     : invalidValue = null,
       _hasValue = false,
       name = null;

  /**
   * 创建包含无效值[value]的Error。
   *
   * 通过向[message]参数添加[name]（如果设置）和`value`后缀来构建message。例如
   *
   *     "Invalid argument (foo): null"
   *
   * `name`应该与函数的参数名相匹配，但如果函数是一个实现接口的方法，
   * 并且它的参数名与接口不同，
   * 那么使用接口中方法的参数名可能更实用（或重命名参数名称）。
   */
  ArgumentError.value(value,
                      [String this.name,
                       String this.message])
      : invalidValue = value,
        _hasValue = true;

  /**
   * 为不能是空值的`null`参数创建Error。
   */
  ArgumentError.notNull([this.name])
      : _hasValue = false,
        message = "Must not be null",
        invalidValue = null;

  // Helper functions for toString overridden in subclasses.
  String get _errorName => "Invalid argument${!_hasValue ? "(s)" : ""}";
  String get _errorExplanation => "";

  String toString() {
    String nameString = "";
    if (name != null) {
      nameString = " ($name)";
    }
    var message = (this.message == null) ? "" : ": ${this.message}";
    String prefix = "$_errorName$nameString$message";
    if (!_hasValue) return prefix;
    // If we know the invalid value, we can try to describe the problem.
    String explanation = _errorExplanation;
    String errorValue = Error.safeToString(invalidValue);
    return "$prefix$explanation: $errorValue";
  }
}

/**
 * 当索引超出有效范围时，Error被抛出。
 */
class RangeError extends ArgumentError {
  /** [value]被允许的最小值。 */
  final num start;
  /** [value]被允许的最大值。 */
  final num end;

  // TODO(lrn): This constructor should be called only with string values.
  // It currently isn't in all cases.
  /**
   * 使用[message]创建一个新的[RangeError]。
   */
  RangeError(var message)
      : start = null, end = null, super(message);

  /**
   * 使用[value]创建一个新的[RangeError]。
   *
   * 可选参数[name]指定有无效参数的参数名，
   * [message]可以重写默认的Error描述。
   */
  RangeError.value(num value, [String name, String message])
      : start = null, end = null,
        super.value(value, name,
                    (message != null) ? message : "Value not in range");

  /**
   * 创建一个新的[RangeError]，表明使用一个超出范围的无效值。
   *
   * 允许的范围是从[minValue]至[maxValue]，包括最大值与最小值。
   * 如果`minValue`或`maxValue`是`null`，那么那个方向的范围是无限的。
   *
   * 如果范围的最小值是0，最大值是索引的长度，
   * 并且不包括最大值，使用[RangeError.index]。
   *
   * 可选参数[name]指定有无效参数的参数名，
   * [message]可以重写默认的Error描述。
   */
  RangeError.range(num invalidValue, int minValue, int maxValue,
                   [String name, String message])
      : start = minValue,
        end = maxValue,
        super.value(invalidValue, name,
                    (message != null) ? message : "Invalid value");

  /**
   * 创建一个新的[RangeError]，表明[index]并不是[indexable]的有效索引。
   *
   * 可选参数[name]指定有无效参数的参数名，
   * [message]可以重写默认的Error描述。
   *
   * [length]是出错时[indexable]的长度。
   * 如果`length`被省略，默认值为`indexable.length`。
   */
  factory RangeError.index(int index, indexable,
                           [String name,
                            String message,
                            int length]) = IndexError;

  /**
   * 检查[value]位于指定区间的。
   *
   * 如果[value]不在区间内，则抛出RangeError。
   * 区间为`minValue <= value <= maxValue`，包括最大值与最小值。
   */
  static void checkValueInInterval(int value, int minValue, int maxValue,
                                   [String name, String message]) {
    if (value < minValue || value > maxValue) {
      throw new RangeError.range(value, minValue, maxValue, name, message);
    }
  }

  /**
   * 检查对于可索引对象，值是一个有效的所有。
   *
   * 如果[index]对于[indexable]并不是一个有效的所有，则抛出RangeError。
   *
   * 可索引对象是指具有`length`属性，
   * 索引操作符`[]`可以接受`0 <= index < length`范围内索引的对象。
   *
   * 如果设置了[length]参数，它将用作可索引对象的length。
   * 否则，length的值等于`indexable.length`。
   */
  static void checkValidIndex(int index, var indexable,
                              [String name, int length, String message]) {
    if (length == null) length = indexable.length;
    // Comparing with `0` as receiver produces better dart2js type inference.
    if (0 > index || index >= length) {
      if (name == null) name = "index";
      throw new RangeError.index(index, indexable, name, message, length);
    }
  }

  /**
   * 检查一个范围是可索引对象的索引范围的子区间。
   *
   * 如果范围对于指定[length]的可索引对象无效，则抛出RangeError。
   *
   * 如果`0 <= [start] <= [end] <= [length]`，那么范围有效。
   * 如果`end`的值是`null`，则被认为等于`length`。
   *
   * 参数[startName]和[endName]的默认值分别是`"start"`和`"end"`。
   *
   * 返回实际的结束值`end`，
   * 如果`end`是`null`，返回`length`。否则，返回`end`。
   */
  static int checkValidRange(int start, int end, int length,
                              [String startName, String endName,
                               String message]) {
    // Comparing with `0` as receiver produces better dart2js type inference.
    // Ditto `start > end` below.
    if (0 > start || start > length) {
      if (startName == null) startName = "start";
      throw new RangeError.range(start, 0, length, startName, message);
    }
    if (end != null) {
      if (start > end || end > length) {
        if (endName == null) endName = "end";
        throw new RangeError.range(end, start, length, endName, message);
      }
      return end;
    }
    return length;
  }

  /**
   * 检查一个整数不是负数。
   *
   * 如果值是负数，抛出RangeError。
   */
  static void checkNotNegative(int value, [String name, String message]) {
    if (value < 0) throw new RangeError.range(value, 0, null, name, message);
  }

  String get _errorName => "RangeError";
  String get _errorExplanation {
    assert(_hasValue);
    String explanation = "";
    if (start == null) {
      if (end != null) {
        explanation = ": Not less than or equal to $end";
      }
      // If both are null, we don't add a description of the limits.
    } else if (end == null) {
      explanation = ": Not greater than or equal to $start";
    } else if (end > start) {
      explanation = ": Not in range $start..$end, inclusive";
    } else if (end < start) {
      explanation = ": Valid value range is empty";
    } else {
      // end == start.
      explanation = ": Only valid value is $start";
    }
    return explanation;
  }
}

/**
 * 专业的[RangeError]，当索引不在`0..indexable.length-1`范围内时使用。
 *
 * 包含获取可索引对象、出错时它的长度、无效值本身等功能
 */
class IndexError extends ArgumentError implements RangeError {
  /** 可索引对象，[index]对于它并不是一个有效的索引。 */
  final indexable;
  /** 在出错时[indexable]的长度。 */
  final int length;

  /**
   * 创建一个新的[IndexError]，表明[invalidValue]对于[indexable]是一个无效的索引。
   *
   * [length]是出错时[indexable]的长度。
   * 如果`length`被省略，默认值为`indexable.length`。
   *
   * `message`被用作Error字符串表示的一部分。
   */
  IndexError(int invalidValue, indexable,
             [String name, String message, int length])
      : this.indexable = indexable,
        this.length = (length != null) ? length : indexable.length,
        super.value(invalidValue, name,
                    (message != null) ? message : "Index out of range");

  // Getters inherited from RangeError.
  int get start => 0;
  int get end => length - 1;

  String get _errorName => "RangeError";
  String get _errorExplanation {
    assert(_hasValue);
    if (invalidValue < 0) {
      return ": index must not be negative";
    }
    if (length == 0) {
      return ": no indices are valid";
    }
    return ": index should be less than $length";
  }
}


/**
 * 当控制权到达switch case表达式的末尾时，Error被抛出。
 *
 * 当控制权到达switch case表达式的末尾时（除最后一个case语句以外），
 * 如果并没有遇到break或者类似的控制流程终止语句，Dart规范要求此Error被抛出。
 */
class FallThroughError extends Error {
  FallThroughError();
}

/**
 * 当试图实例化一个抽象类（abstract class）时，Error被抛出。
 */
class AbstractClassInstantiationError extends Error {
  final String _className;
  AbstractClassInstantiationError(String this._className);
  String toString() => "Cannot instantiate abstract class: '$_className'";
}


/**
 * 被[Object]中默认实现的[:noSuchMethod:]方法抛出。
 */
class NoSuchMethodError extends Error {
  final Object _receiver;
  final Symbol _memberName;
  final List _arguments;
  final Map<Symbol, dynamic> _namedArguments;
  final List _existingArgumentNames;

  /**
   * 创建[NoSuchMethodError]，同时与失败的方法调用相对应。
   *
   * [receiver]是方法调用的接收者，也就是试图调用方法的对象。
   * 如果接收者是`null`，它将被理解成调用了一个库的顶层函数。
   *
   * [memberName]是[Symbol]类型，表示调用的方法或访问器的名称。它不应该是`null`。
   *
   * [positionalArguments]是一个List，保存有方法被调用时，使用的位置参数。
   * 如果是`null`，则被视为空列表。
   *
   * [namedArguments]是一个Map，
   * key是[Symbol]，value是方法被调用时，使用的命名参数。
   *
   * [existingArgumentNames]（可选）是一个方法被调用时，
   * 期望的、正确的参数类型名称，如果可用的话。
   * 例如，`print(1, 2)`会抛出错误，并显示`Found: print(Object)`，
   * 这个时候，
   *     existingArgumentNames == ["Object"];
   */
  NoSuchMethodError(Object receiver,
                    Symbol memberName,
                    List positionalArguments,
                    Map<Symbol ,dynamic> namedArguments,
                    [List existingArgumentNames = null])
      : _receiver = receiver,
        _memberName = memberName,
        _arguments = positionalArguments,
        _namedArguments = namedArguments,
        _existingArgumentNames = existingArgumentNames;

  external String toString();
}


/**
 * 对象不允许的操作。
 *
 * 当一个实例不能实现签名中的方法时，[Error]被抛出。
 */
class UnsupportedError extends Error {
  final String message;
  UnsupportedError(this.message);
  String toString() => "Unsupported operation: $message";
}


/**
 * 操作还没有被实现。
 *
 * [Error]是由未完成的代码抛出的，因为还未实现它所需要的所有功能。
 *
 * 如果一个类并不打算实现功能，它应该抛出[UnsupportedError]来代替。
 * [UnimplementedError]的目的仅仅只是在开过过程中使用。
 */
class UnimplementedError extends Error implements UnsupportedError {
  final String message;
  UnimplementedError([String this.message]);
  String toString() => (this.message != null
                        ? "UnimplementedError: $message"
                        : "UnimplementedError");
}


/**
 * 在对象的当前状态，操作不被允许。
 *
 * 这是针对各种不同错误的通用的[Error]，应在message中进行描述。
 */
class StateError extends Error {
  final String message;
  StateError(this.message);
  String toString() => "Bad state: $message";
}


/**
 * 在迭代过程中集合被修改时，Error被抛出。
 *
 * 一些集合允许部分修改操作。
 * 因此，每个集合（[Iterable]或类似值的集合）应该声明在迭代期间哪些操作是被允许的。
 */
class ConcurrentModificationError extends Error {
  /** 用不兼容的方式修改的对象。 */
  final Object modifiedObject;

  ConcurrentModificationError([this.modifiedObject]);

  String toString() {
    if (modifiedObject == null) {
      return "Concurrent modification during iteration.";
    }
    return "Concurrent modification during iteration: "
           "${Error.safeToString(modifiedObject)}.";
  }
}


class OutOfMemoryError implements Error {
  const OutOfMemoryError();
  String toString() => "Out of Memory";

  StackTrace get stackTrace => null;
}


class StackOverflowError implements Error {
  const StackOverflowError();
  String toString() => "Stack Overflow";

  StackTrace get stackTrace => null;
}

/**
 * 在惰性初始化时，变量不能被初始化，Error被抛出。
 *
 * 使用初始化表达式对static/library级别的变量进行初始化操作，是在第一次读的时候。
 * 在对初始化表达式求值时，如果循环读取初始化变量的值，Error被抛出。
 * 例如，
 *     int i = j + 1;
 *     int j = i + 1;
 */
class CyclicInitializationError extends Error {
  final String variableName;
  CyclicInitializationError([this.variableName]);
  String toString() => variableName == null
      ? "Reading static variable during its initialization"
      : "Reading static variable '$variableName' during its initialization";
}
